package server;
import java.io.*;
import java.net.*;
import java.util.*;
import netPacks.message;
/**
 *
 * @author user
 */
public class mainServer extends Thread{
    LinkedList<clientConnection> userQ = new LinkedList<clientConnection>();
    LinkedList<clientConnection> readyQ = new LinkedList<clientConnection>();
    ServerSocket serverSocket = null;
    InetAddress ip = null;
    final int DEFAULT_PORT = 5005;
    final int DEFAULT_BACKUP_PORT = 6000;
    int port = DEFAULT_PORT;
    boolean isBackup = false;
    InetAddress backupAddress = null;
    int backupPort = DEFAULT_BACKUP_PORT;
    
    private static volatile mainServer instance = null;
    
    private mainServer(){
        try {
            ip =InetAddress.getLocalHost();
        }
        catch(Exception e){
            System.err.println("Cannot aquire local IP address:\n" + e.getMessage());
        }
    }
    
    public static mainServer getInstance() {
        if (instance == null){
            synchronized (mainServer.class){
                    if (instance == null){
                        instance = new mainServer();
                    }
            }
        }
        return instance;
    }
    
    @Override
    public synchronized void run(){
        try{
            serverSocket = new ServerSocket(this.port);
            System.out.println("Listening on port: "+this.port);
        }
        catch(IOException e){
            System.err.println("Cannot create socket on port: "+mainServer.getInstance().port+"\n" + e.getMessage());
            System.err.println("Please restart using an available port.");
            System.exit(1);
        }
        try{
                while(true){
                    System.out.println("Waiting for connections.");
                	Socket clientSocket = serverSocket.accept();
                	clientConnection c = new clientConnection(clientSocket);
                    System.out.println("Accepted a connection from: "+clientSocket.getInetAddress());
                    c.start();
                    message tmpMsg = new message();
                    tmpMsg.setAction("backupAddress");
                    tmpMsg.setData(this.backupAddress.toString());
                    tmpMsg.setUserId(this.ip);
                    c.oos.writeObject(tmpMsg);
                    this.addUser(c);
                    //TODO: add backup server update here.
                    System.out.println("Waiting for client to be Ready.");
                    System.out.println("Sending backup data");  
                    c.pingy.start();
                    c.pingyCheck.start();
                }
        }
            catch(Exception e) {
            	e.printStackTrace();
            }
    }
    
    public synchronized void addUser(clientConnection client){
    	for(Iterator<clientConnection> it=readyQ.iterator(); it.hasNext(); ){
    		if(it.next().getClientId().equals(client.id)){
    			message refreshMsg = new message();
    			refreshMsg.setAction("refreshCon");
    			refreshMsg.setUserId(client.id);
    			try{
    				client.oos.writeObject(refreshMsg);
    			}
    			catch(IOException e){
    				System.err.println("Unable to send disconnect message previous connection. Continuing...");
    			}
    			it.remove();
    			System.out.println("Connection already found. Creating new one...");
    		}
    	}
    	for(Iterator<clientConnection> it=userQ.iterator(); it.hasNext(); ){
    		if(it.next().getClientId().equals(client.id)){
    			message refreshCon = new message();
    			refreshCon.setAction("refreshCon");
    			refreshCon.setUserId(client.id);
    			try{
    				client.oos.writeObject(refreshCon);
    			}
    			catch(IOException e){
    				System.err.println("Unable to send disconnect message previous connection. Continuing...");
    			}
    			it.remove();
    			System.out.println("Connection already found. Creating new one...");
    		}
    	}
    	this.userQ.add(client);
    	System.out.println("User added");
    }
    
    public synchronized Object popReady(){
        return this.readyQ.pop();
    }
    
    public void setIsBackup(boolean is){
    	this.isBackup = is;
    }
    
    public boolean getIsBackup(){
    	return this.isBackup;
    }
    
    public void setBackupAddress(InetAddress add){
    	this.backupAddress = add;
    }
    
    public InetAddress getBackupAddress(){
    	return this.backupAddress;
    }
    
    public void setWorkingPort(int port){
    	this.port = port;
    }
    
    public int getWorkingPort(){
    	return this.port;
    }
    
    public void setBackupPort(int port){
    	this.backupPort = port;
    }
    
    public int getBackupPort(){
    	return this.backupPort;
    }
    
    public void terminateServer(){
        try {
            System.out.println("Closing Socket...");
            this.serverSocket.close();
            System.out.println("DONE. Exiting...");
            System.exit(1);
        }
            catch(IOException e){
            System.err.println("Cannot close socket connections:"+"\n" + e.getMessage());
        }
    }
}
